<template>
  <div>
    <!-- 编辑器 -->
    <div class="wangeditorStyle border-1 border-solid border-#ccc z-99">
      <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :editorId="editorId"
        :defaultConfig="toolbarConfig" :mode="mode" />
      <Editor :style="styles" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" :editorId="editorId"
        @onCreated="handleCreated" @onChange="handleChange" @onBlur="handleBlur" />
    </div>
    <!-- 上传本地文件 start -->
    <el-upload class="avatar-uploader-editor" action="#" :before-upload="beforeAvatarUpload"
      accept=".mp3, .wma, .Aac, .ogg, .mpc" :show-file-list="false">
      <el-button type="default" style="display: none; font-size: 14px"><el-icon>
          <UploadFilled />
        </el-icon>上传</el-button>
    </el-upload>
    <!-- 网络音频 -->
    <NetworkModel :dialogParam="audioNetwork" @ok="modelValOK" @close="audioNetwork.isVisible = false"></NetworkModel>
    <!-- 素材上传 -->
    <MaterialModel :dialogParam="materialParam" @ok="modelValOK" @close="materialParam.isVisible = false">
    </MaterialModel>
  </div>
</template>
<script setup name="MyEditor">
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted, computed } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { SlateTransforms } from '@wangeditor/editor'
import registerMenu from './toolbars/index'
import setToolbarKeys from './utils/setConfig'
import { getBase64 } from './utils/index'
import { isNumber } from '@/utils/validate'
/*** 自定义插件 */
import customAlert from './plugin/customAlert'
// 业务组件
import NetworkModel from './editorComponents/NetworkModel.vue'
import MaterialModel from './editorComponents/materialModel.vue'
const { proxy } = getCurrentInstance()
const props = defineProps({
  /* 编辑器的内容 */
  modelValue: {
    type: String
  },
  /*** 编辑器id */
  editorId: {
    type: String,
    default: 'wangeEditor-1'
  },
  /**配置项 */
  setEditorToolbar: {
    type: Array,
    default: () => undefined
  },
  /* 高度 */
  height: {
    type: Number,
    default: 500
  },
  /* 只读 */
  readonly: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['change', 'update:modelValue', 'previewPage'])
// 编辑器内容 html
const valueHtml = ref(null)
/******************************************* 配置 start *****************/
// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef()
const mode = ref('default')
/**** 工具栏配置 */
const toolbarConfig = {
  toolbarKeys:
    props.setEditorToolbar && props.setEditorToolbar.length > 0
      ? props.setEditorToolbar
      : setToolbarKeys
}
/**** 编辑器配置 */
const editorConfig = computed(() => {
  return Object.assign({
    placeholder: '请输入内容...',
    readOnly: props.readonly,
    autoFocus: false,
    scroll: true,
    MENU_CONF: {
      // 上传本地图片
      uploadImage: {
        /**
         *
         * @param {*} file 文件
         * @param {*} insertFn 输入到编辑器
         */
        async customUpload(file, insertFn) {
          if (file.size / 1024 / 1024 > 5) {
            customAlert('单个文件不能超过5MB!', 'warning')
            return false
          }
          // 把图片转成base64
          getBase64(file, url => {
            insertFn(url)
          })
        }
      },
      // 上传本地视频
      uploadVideo: {
        async customUpload(file, insertFn) {
          const url = 'https://www.runoob.com/try/demo_source/movie.ogg'
          insertFn(url)
        }
      }
    }
  })
})
/**** 自定义扩展新功能 */
//注册自定义菜单点击事件 事件监听
const audioNetwork = ref({})
const materialParam = ref({})
const initMediaMenuEvent = () => {
  const editor = editorRef.value
  /*** 音频模块 start */
  editor.on('audioNetworkClick', () => {
    audioNetwork.value.isVisible = true
    editor.hidePanelOrModal()
  })
  editor.on('audioLocalClick', () => {
    // 本地音频
    console.log('本地音频')
    document.querySelector('.avatar-uploader-editor input').click() //触发input框选择图片文件
  })
  /**
   *素材音频以及素材上传
   * type 类型
   */
  editor.on('materialClick', type => {
    // 素材音频
    materialParam.value.isVisible = true
    materialParam.value.type = type
    switch (type) {
      case 'audio':
        editor.insertBreak() //换行
        materialParam.value.title = '请选择音频'
        break
      case 'image':
        materialParam.value.title = '请选择图片'
        break
      case 'video':
        editor.insertBreak() //换行
        materialParam.value.title = '请选择视频'
        break
    }
    editor.hidePanelOrModal()
  })
  /**预览页面 */
  editor.on('PreviewPageClick', () => {
    emit('previewPage', 'previewPage')
  })
}
/**
 * 弹出框 确定回调事件
 * @param {*} row 获取的参数
 */
const modelValOK = row => {
  const editor = editorRef.value
  let node = []
  let current_path = null
  switch (row.type) {
    case 'audioNetwork':
      // 网络音频
      current_path = getSelection()
      audioNetwork.value.isVisible = false
      if (!row.data.url) {
        return false
      }
      node.push({
        type: 'video',
        poster: row.data.poster || '',
        src: row.data.url,
        children: [{ text: 'ddd' }] // 该字段必须要
      })
      SlateTransforms.insertNodes(editor, node, { at: [current_path] })
      break
    case 'image':
      // 素材图片
      materialParam.value.isVisible = false
      if (!row.data || row.data.length == 0) {
        return false
      }
      node = JSON.parse(JSON.stringify(row.data))
      node.map(value => {
        value.type = 'image'
        value.src = value.url
        value.children = [{ text: value.name }] // 该字段必须要
      })
      SlateTransforms.insertNodes(editor, node)
      break
    default:
      current_path = getSelection()
      // 素材音频 视频
      materialParam.value.isVisible = false
      if (!row.data || row.data.length == 0) {
        editor.undo() //撤销
        return false
      }
      node = JSON.parse(JSON.stringify(row.data))
      node.map(value => {
        value.type = 'video'
        value.src = value.url
        value.children = [{ text: value.name }] // 该字段必须要
      })
      SlateTransforms.insertNodes(editor, node, { at: [current_path] })
      break
  }
}
/**
 * 获取鼠标指定的位置
 */
const getSelection = () => {
  const editor = editorRef.value
  const len = editor.history?.undos?.length
  let current_path = 0
  if (len == 0) {
    //第一个节点的时候首行 第一个文字
    current_path = 0
  } else {
    const el = editor.history.undos[len - 1]?.length
    let path = []
    if (el > 0) {
      const obj = editor.history.undos[len - 1][el - 1]
      console.log(obj, 'obj---')
      if (obj.type == 'set_selection') {
        // 选区是空白的情况
        console.log(
          obj.newProperties,
          obj.newProperties.anchor,
          obj.newProperties.anchor.path,
          'newProperties'
        )
        path = obj.newProperties.anchor.path
      } else {
        path = obj.path
      }
      if (path.length == 1) {
        current_path = path[0] == 0 ? 1 : path[0] + 1
      } else {
        if (path[0] == 0 && path[1] == 0) {
          current_path = path[0] + 1
        } else {
          current_path = path[0] == 0 ? 1 : path[0] + 1
        }
      }
    }
    console.log(path[0], current_path, 'el<0')
  }
  return current_path
}
/*本地音频上传 限制条件
 *
 * @param {*} rawFile
 */
function beforeAvatarUpload(rawFile) {
  if (rawFile.size / 1024 / 1024 > 5) {
    proxy.$modal.msgError('单个文件不能超过5MB!')
    return false
  }
  // let current_path = getSelection()
  const node = [
    {
      type: 'video',
      src: 'https://www.runoob.com/try/demo_source/horse.mp3',
      children: [{ text: 'bbb' }]
    }
  ]
  SlateTransforms.insertNodes(editorRef.value, node)
  // SlateTransforms.insertNodes(editorRef.value, node, { at: [current_path] })
}
//创建实例触发的事件
const handleCreated = editor => {
  editorRef.value = editor // 记录 editor 实例，重要！
  registerMenu(editor, toolbarConfig) // 注册自定义菜单
  initMediaMenuEvent() // 注册自定义菜单点击事件
}
// 回调函数 值发生改变触发
const handleChange = editor => {
  emit('change', editor)
}
const handleBlur = editor => { }

/******************************************* 配置 end *****************/
const styles = computed(() => {
  let style = {}
  if (props.height) {
    style.height = isNumber(props.height) ? `${props.height}px` : props.height
  }
  style.overflowY = 'hidden'
  return style
})
// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy() // 销毁，并移除 editor
})

watch(
  () => props.modelValue,
  v => {
    if (v === unref(valueHtml)) return
    valueHtml.value = v
  },
  { immediate: true }
)
// 监听
watch(
  () => valueHtml.value,
  val => {
    emit('update:modelValue', val)
  }
)
</script>
<style lang="scss">
.wangeditorStyle {

  // border: 1px solid #ccc;
  .dropPanelSelStyle {
    .btn {
      display: block;
      width: 100%;
      text-align: left;

      svg {
        vertical-align: text-bottom;
      }
    }
  }
}
</style>
